Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
Registered S3 method overwritten by 'cli':
  method     from    
  print.boxx spatstat
── Attaching packages ─────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble  3.0.6     ✓ dplyr   1.0.4
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
✓ purrr   0.3.4     
── Conflicts ────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::between()   masks data.table::between()
x tidyr::expand()    masks Matrix::expand()
x dplyr::filter()    masks plotly::filter(), stats::filter()
x dplyr::first()     masks data.table::first()
x dplyr::lag()       masks stats::lag()
x dplyr::last()      masks data.table::last()
x tidyr::pack()      masks Matrix::pack()
x purrr::transpose() masks data.table::transpose()
x tidyr::unpack()    masks Matrix::unpack()

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

The following object is masked from ‘package:plotly’:

    select

---------------------
Welcome to dendextend version 1.14.0
Type citation('dendextend') for how to cite the package.

Type browseVignettes(package = 'dendextend') for the package vignette.
The github page is: https://github.com/talgalili/dendextend/

Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
Or contact: <tal.galili@gmail.com>

    To suppress this message use:  suppressPackageStartupMessages(library(dendextend))
---------------------


Attaching package: ‘dendextend’

The following object is masked from ‘package:data.table’:

    set

The following object is masked from ‘package:stats’:

    cutree

To demostrate how to do the gene clustering usign COTAN we begin importing the COTAN object that stores all elaborated data and, in this case, regarding a mouse embrionic cortex dataset (developmental stage E17.5).

[1] "calculating gene coexpression space: output tanh of reduced coex matrix"
     L11      L12    L2/31    L2/32      L41      L42    L5/61    L5/62    Prog1    Prog2 
  "Reln"   "Lhx5"  "Satb2"   "Cux1"   "Rorb"   "Sox5" "Bcl11b"  "Fezf2"    "Vim"   "Hes1" 
[1] "Get p-values on a set of genes on columns genome wide on rows"
[1] "Using function S"
[1] "function to generate S "
[1] "function to generate S "

Hierarchical clustering

or just with primary markers

Now we can plot the PCA

# some more genes as landmarks
controls =list("genes related to L5/6"=c("Foxp2","Tbr1"), "genes related to L2/3"=c("Mef2c"), "genes related to Prog"=c("Nes","Sox2") , "genes related to L1"=c() , "genes related to L4"=c()) 

# dataframe to be able to label only primary markers and control genes
textdf <- pca_1[rownames(pca_1) %in% c(unlist(layers),unlist(controls)) , ]

 for (m in c(1:length(controls))) {
  for (g in controls[[m]]) {
    if(g %in% rownames(textdf)){
      textdf[g,"highlight"] = names(controls[m])
    } 
  }
}

# deciding the colors
mycolours <- c("genes related to L5/6" = "#3C5488FF","genes related to L2/3"="#F39B7FFF","genes related to Prog"="#4DBBD5FF","genes related to L1"="#E64B35FF","genes related to L4" = "#91D1C2FF", "not marked"="#B09C85FF")

# to assing correcly the cluster number and the color
mycolours2 = c("Reln","Satb2","Rorb","Bcl11b","Vim")
names(mycolours2) = unique(cut[unlist(layers)])

mycolours2[mycolours2 == "Reln"] = "#E64B35FF"
mycolours2[mycolours2 == "Satb2"] = "#F39B7FFF"
mycolours2[mycolours2 == "Rorb"] = "#91D1C2FF"
mycolours2[mycolours2 == "Bcl11b"] = "#3C5488FF"
mycolours2[mycolours2 == "Vim"] = "#4DBBD5FF"
color_to_add = unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]
names(color_to_add) = unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]
color_to_add[color_to_add %in% 
                 unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]] = "#B09C85FF"
mycolours2 = c(mycolours2,color_to_add)

pca1 = ggplot(subset(pca_1,!hclust %in% unique(cut[unlist(layers)])  ), aes(x=PC1, y=PC2)) +  geom_point(alpha = 0.3,color = "#B09C85FF",size=1)

#pca2 = pca1 + geom_point(data = subset(pca_1, highlight != "not marked" ), aes(x=PC1, y=PC2, colour=hclust),size=2.5,alpha = 0.9) 
pca2 = pca1 + geom_point(data = subset(pca_1, hclust %in% unique(cut[unlist(layers)]) ), aes(x=PC1, y=PC2, colour=as.character(hclust)),size=1,alpha = 0.5) + 
 scale_color_manual( "Status", values = mycolours2)  +
  scale_fill_manual( "Status", values = mycolours2)  +
  xlab("") + ylab("") +
  geom_label_repel(data =textdf , aes(x = PC1, y = PC2, label = rownames(textdf),fill=as.character(hclust)),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction = "both",
                   na.rm=TRUE,
                   seed = 1234) +
  geom_label_repel(data =textdf , aes(x = PC1, y = PC2, label = rownames(textdf)),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234) +
  ggtitle("PCA") +
  theme_light(base_size=10) +
    theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.position = "none")  # titl)

pca2 #+ geom_encircle(data = pca_1, aes(group=hclust)) 

t-SNE code and plot

# run the t-SNE
cl.genes.tsne = Rtsne(g.space ,initial_dims = 100, dims = 2, perplexity=30,eta = 200, verbose=F, max_iter = 3000,theta=0.4,num_threads = 10,pca_center = T, pca_scale = FALSE, normalize = T )

d_tsne_1 = as.data.frame(cl.genes.tsne$Y)
rownames(d_tsne_1) = rownames(g.space)

d_tsne_1 = d_tsne_1[order.dendrogram(dend),]

# save the cluster numebr inside a dataframe with the t-SNE information
d_tsne_1$hclust = cut

d_tsne_1$names = rownames(d_tsne_1)

# as before to label only some genes
textdf <- d_tsne_1[rownames(d_tsne_1) %in% c(unlist(layers),unlist(controls)),]

for (m in c(1:length(controls))) {
  for (g in controls[[m]]) {
    if(g %in% rownames(textdf)){
      textdf[g,"highlight"] = names(controls[m])
    } 
  }
}


 p1 = ggplot(subset(d_tsne_1,!hclust %in% unique(cut[unlist(layers)])), aes(x=V1, y=V2)) +  geom_point(alpha = 0.3, color = "#B09C85FF", size=1)

p2 = p1 + geom_point(data = subset(d_tsne_1, hclust %in% unique(cut[unlist(layers)]) ), aes(x=V1, y=V2, colour=as.character(hclust)),size=1,alpha = 0.5) +
    scale_color_manual("Status", values = mycolours2)  +
  scale_fill_manual("Status", values = mycolours2)  +
  xlab("") + ylab("")+
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names,fill=as.character(hclust)),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction = "both",
                   na.rm=TRUE,
                   seed = 1234) +
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234) +
  ggtitle("t-SNE") +
  theme_light(base_size=10) +
  theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.position = "none")  # titl)
p2

Code to create an iteractive plot. This can be modified to be used with all the plots.

Multidimensional scaling (MDS) and plot

initial  value 12.149889 
final  value 10.248596 
converged
fit.genes = as.data.frame(fit$points)

fit.genes = fit.genes[order.dendrogram(dend),]

fit.genes$hclust = cut


fit.genes$names = rownames(fit.genes)

mycolours3 <- c("cluster L5/6 markers" = "#3C5488FF","cluster L2/3 markers"="#F39B7FFF","cluster Prog markers"="#4DBBD5FF","cluster L1 markers"="#E64B35FF","cluster L4 markers" = "#91D1C2FF", "not identified cluster"="#B09C85FF")

#fit.genes$hclust = factor(cutree(hc.norm, 7))
used = vector()
for (k in c(1:length(layers))) {
  #print(k)
  tt =as.numeric(cut[layers[[k]]][1])
  fit.genes[fit.genes$hclust == tt,"cluster"] = paste("cluster",names(layers[k]),"markers", sep = " " )
  used = c(used,cut[layers[[k]]][1])
}

fit.genes[fit.genes$hclust %in% (unique(fit.genes$hclust)[!unique(fit.genes$hclust) %in% used]),]$cluster = "not identified cluster"

textdf <- fit.genes[rownames(fit.genes) %in% c(unlist(layers),unlist(controls)),]

   f1 = ggplot(subset(fit.genes,!hclust %in% unique(cut[unlist(layers)]) ), aes(x=V1, y=V2)) +  geom_point(alpha = 0.3, color = "#B09C85FF", size=1)

f2 = f1 + geom_point(data = subset(fit.genes, hclust %in% unique(cut[unlist(layers)]) ), 
                     aes(x=V1, y=V2, colour=cluster), size=1,alpha = 0.5) +
  scale_color_manual("Status", values = mycolours3)  +
  scale_fill_manual("Status", values = mycolours3)  + 
  xlab("") + ylab("")+
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = rownames(textdf),fill=cluster),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction ="both",
                   na.rm=TRUE,
                   seed = 1234, show.legend = FALSE) +
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = rownames(textdf)),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234, show.legend = FALSE) +
  ggtitle("MDS") +
  theme_light(base_size=10) +
  theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.title = element_blank(),
        legend.text = element_text(color = "#3C5488FF",face ="italic" ),
        legend.position = "bottom")  # titl)


f2 #+ geom_encircle(data = fit.genes, aes(group=`5_clusters`)) 

R version 4.0.4 (2021-02-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] dendextend_1.14.0 MASS_7.3-53.1     htmlwidgets_1.5.3 forcats_0.5.1     stringr_1.4.0     dplyr_1.0.4      
 [7] purrr_0.3.4       readr_1.4.0       tidyr_1.1.2       tibble_3.0.6      tidyverse_1.3.0   plotly_4.9.3     
[13] Rtsne_0.15        factoextra_1.0.7  ggrepel_0.9.1     ggplot2_3.3.3     Matrix_1.3-2      data.table_1.13.6
[19] COTAN_0.1.0      

loaded via a namespace (and not attached):
  [1] readxl_1.3.1         backports_1.2.1      circlize_0.4.12      plyr_1.8.6           igraph_1.2.6        
  [6] lazyeval_0.2.2       splines_4.0.4        crosstalk_1.1.1      listenv_0.8.0        scattermore_0.7     
 [11] digest_0.6.27        htmltools_0.5.1.1    viridis_0.5.1        magrittr_2.0.1       tensor_1.5          
 [16] cluster_2.1.1        ROCR_1.0-11          openxlsx_4.2.3       ComplexHeatmap_2.6.2 globals_0.14.0      
 [21] modelr_0.1.8         matrixStats_0.58.0   colorspace_2.0-0     rvest_0.3.6          rappdirs_0.3.3      
 [26] haven_2.3.1          xfun_0.20            crayon_1.4.0         jsonlite_1.7.2       spatstat_1.64-1     
 [31] spatstat.data_2.0-0  survival_3.2-7       zoo_1.8-8            glue_1.4.2           polyclip_1.10-0     
 [36] gtable_0.3.0         leiden_0.3.7         GetoptLong_1.0.5     car_3.0-10           future.apply_1.7.0  
 [41] shape_1.4.5          BiocGenerics_0.36.0  abind_1.4-5          scales_1.1.1         DBI_1.1.1           
 [46] rstatix_0.7.0        miniUI_0.1.1.1       Rcpp_1.0.6           viridisLite_0.3.0    xtable_1.8-4        
 [51] clue_0.3-58          reticulate_1.18      foreign_0.8-81       latex2exp_0.4.0      stats4_4.0.4        
 [56] httr_1.4.2           RColorBrewer_1.1-2   ellipsis_0.3.1       Seurat_4.0.0         ica_1.0-2           
 [61] pkgconfig_2.0.3      farver_2.0.3         sass_0.3.1           uwot_0.1.10          dbplyr_2.1.0        
 [66] deldir_0.2-10        tidyselect_1.1.0     labeling_0.4.2       rlang_0.4.10         reshape2_1.4.4      
 [71] later_1.1.0.1        cellranger_1.1.0     munsell_0.5.0        tools_4.0.4          cli_2.3.0           
 [76] generics_0.1.0       broom_0.7.5          ggridges_0.5.3       evaluate_0.14        fastmap_1.1.0       
 [81] yaml_2.2.1           goftest_1.2-2        fs_1.5.0             knitr_1.31           fitdistrplus_1.1-3  
 [86] zip_2.1.1            RANN_2.6.1           pbapply_1.4-3        future_1.21.0        nlme_3.1-152        
 [91] mime_0.9             xml2_1.3.2           rstudioapi_0.13      compiler_4.0.4       curl_4.3            
 [96] filelock_1.0.2       png_0.1-7            ggsignif_0.6.1       spatstat.utils_2.0-0 reprex_1.0.0        
[101] bslib_0.2.4          stringi_1.5.3        basilisk.utils_1.2.2 lattice_0.20-41      vctrs_0.3.6         
[106] pillar_1.4.7         lifecycle_0.2.0      lmtest_0.9-38        jquerylib_0.1.3      GlobalOptions_0.1.2 
[111] RcppAnnoy_0.0.18     cowplot_1.1.1        irlba_2.3.3          httpuv_1.5.5         patchwork_1.1.1     
[116] R6_2.5.0             promises_1.1.1       rio_0.5.16           KernSmooth_2.23-18   gridExtra_2.3       
[121] IRanges_2.24.1       parallelly_1.23.0    codetools_0.2-18     assertthat_0.2.1     rjson_0.2.20        
[126] withr_2.4.1          SeuratObject_4.0.0   sctransform_0.3.2    S4Vectors_0.28.1     mgcv_1.8-33         
[131] parallel_4.0.4       hms_1.0.0            grid_4.0.4           rpart_4.1-15         basilisk_1.2.1      
[136] rmarkdown_2.7        carData_3.0-4        Cairo_1.5-12.2       ggpubr_0.4.0         shiny_1.6.0         
[141] lubridate_1.7.9.2   
LS0tCnRpdGxlOiAiR2VuZV9jbHVzdGVyaW5nIgpvdXRwdXQ6CiAgICBodG1sX25vdGVib29rOgogICAgICBjc3M6IGh0bWwtbWQtMDEuY3NzCiAgICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICAgIHRoZW1lOiBzcGFjZWxhYgogICAgICB0b2M6IHllcwogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgY29sbGFwc2VkOiBubwotLS0KCmBgYHtyLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb2xsYXBzZSA9IFRSVUUsCiAgY29tbWVudCA9ICIjPiIsCiAgZmlnLndpZHRoID0gNywKICBmaWcuaGVpZ2h0ID0gNwopCmBgYAoKYGBge3Igc2V0dXB9CgpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkoQ09UQU4pCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShSdHNuZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZGVuZGV4dGVuZCkKYGBgCgpUbyBkZW1vc3RyYXRlIGhvdyB0byBkbyB0aGUgZ2VuZSBjbHVzdGVyaW5nIHVzaWduIENPVEFOIHdlIGJlZ2luIGltcG9ydGluZyB0aGUgQ09UQU4gb2JqZWN0IHRoYXQgc3RvcmVzIGFsbCBlbGFib3JhdGVkIGRhdGEgYW5kLCBpbiB0aGlzIGNhc2UsIHJlZ2FyZGluZyBhIG1vdXNlIGVtYnJpb25pYyBjb3J0ZXggZGF0YXNldCAoZGV2ZWxvcG1lbnRhbCBzdGFnZSBFMTcuNSkuCgpgYGB7cn0KaW5wdXRfZGlyID0gIkRhdGEvIgpsYXllcnMgPSBsaXN0KCJMMSI9YygiUmVsbiIsIkxoeDUiKSwgIkwyLzMiPWMoIlNhdGIyIiwiQ3V4MSIpLCAiTDQiPWMoIlJvcmIiLCJTb3g1IikgLCAiTDUvNiI9YygiQmNsMTFiIiwiRmV6ZjIiKSAsICJQcm9nIj1jKCJWaW0iLCJIZXMxIikpCiNvYmpFMTcgPSByZWFkUkRTKGZpbGUgPSBwYXN0ZShpbnB1dF9kaXIsIkUxNy41X2NvcnRleC5jb3Rhbi5SRFMiLCBzZXAgPSAiIikpCm9iakUxNyA9IHJlYWRSRFMoZmlsZSA9IHBhc3RlKGlucHV0X2RpciwiRTE3LjVfY29ydGV4LmNvdGFuLlJEUyIsIHNlcCA9ICIiKSkKYGBgCgpgYGB7cn0KZy5zcGFjZSA9IGdldC5nZW5lLmNvZXhwcmVzc2lvbi5zcGFjZShvYmpFMTcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uZ2VuZXMuZm9yLm1hcmtlciA9IDI4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5Lm1hcmtlcnMgPSB1bmxpc3QobGF5ZXJzKSkKYGBgCmBgYHtyfQpnLnNwYWNlID0gYXMuZGF0YS5mcmFtZShhcy5tYXRyaXgoZy5zcGFjZSkpCgpjb2V4LnBjYS5nZW5lcyA8LSBwcmNvbXAodChnLnNwYWNlKSwKICAgICAgICAgICAgICAgICBjZW50ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgIHNjYWxlLiA9IEYpIAoKZnZpel9laWcoY29leC5wY2EuZ2VuZXMsIGFkZGxhYmVscz1UUlVFLG5jcCA9IDEwKQojZnZpel9laWcoY29leC5wY2EuZ2VuZXMsIGNob2ljZSA9ICJlaWdlbnZhbHVlIiwgYWRkbGFiZWxzPVRSVUUpCmBgYApIaWVyYXJjaGljYWwgY2x1c3RlcmluZwpgYGB7cn0KCiMgY2x1c3RlcmluZyB1c2lnbiBXYXJkIG1ldGhvZApoYy5ub3JtID0gaGNsdXN0KGRpc3QoZy5zcGFjZSksIG1ldGhvZCA9ICJ3YXJkLkQyIikKCiMgYW5kIGN1dCB0aGUgdHJlZSBpbnRvIDUgY2x1c3RlcnMgKGZvciBleGFtcGxlKQpjdXQgPSBjdXRyZWUoaGMubm9ybSwgayA9IDcsIG9yZGVyX2NsdXN0ZXJzX2FzX2RhdGEgPSBGKQoKIyBJdCBjcmF0ZXMgdGhlIHRyZWUKZGVuZCA8LSBhcy5kZW5kcm9ncmFtKGhjLm5vcm0pCgojIEkgY2FuIHVzZSBhIGRhdGFmcmFtZSBmcm9tIHRoZSBwY2EgdG8gc3RvcmUgc29tZSBkYXRhIHJlZ2FyZGluZyB0aGUgY2x1c3RlcmluZwpwY2FfMSA9IGFzLmRhdGEuZnJhbWUoY29leC5wY2EuZ2VuZXMkcm90YXRpb25bLDE6NV0pCnBjYV8xID0gcGNhXzFbb3JkZXIuZGVuZHJvZ3JhbShkZW5kKSxdCgoKbXljb2xvdXJzIDwtIGMoImdlbmVzIHJlbGF0ZWQgdG8gTDUvNiIgPSAiIzNDNTQ4OEZGIiwiZ2VuZXMgcmVsYXRlZCB0byBMMi8zIj0iI0YzOUI3RkZGIiwiZ2VuZXMgcmVsYXRlZCB0byBQcm9nIj0iIzREQkJENUZGIiwiZ2VuZXMgcmVsYXRlZCB0byBMMSI9IiNFNjRCMzVGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDQiID0gIiM5MUQxQzJGRiIsICJub3QgbWFya2VkIj0iI0IwOUM4NUZGIikKCiMgc2F2ZSB0aGUgY2x1c3RlciBudW1iZXIgaW50byB0aGUgZGF0YWZyYW1lCnBjYV8xJGhjbHVzdCA9IGN1dAoKZGVuZCA9YnJhbmNoZXNfY29sb3IoZGVuZCxrPTcsY29sPWMoIiM0REJCRDVGRiIsIiM5MUQxQzJGRiIsIiNGMzlCN0ZGRiIsIiNFNjRCMzVGRiIsIiMzQzU0ODhGRiIsIiM5MUQxQzJGRiIsIiNCMDlDODVGRiIgKSxncm91cExhYmVscyA9IFQpCiNkZW5kID1jb2xvcl9sYWJlbHMoZGVuZCxrPTUsbGFiZWxzID0gcm93bmFtZXMocGNhXzEpLGNvbD1wY2FfMSRjb2xvcnMpCgoKCiMgcGxvdCB0aGUgZGVuZHJvZ3JhbSB3aXRoIGFsbCBhbm1lcyBmb3Igc2Vjb25kYXJ5IG1hcmtlcnMKZGVuZCAlPiUKICBzZXQoImxhYmVscyIsIGlmZWxzZShsYWJlbHMoZGVuZCkgJWluJSByb3duYW1lcyhwY2FfMSlbcm93bmFtZXMocGNhXzEpICVpbiUgY29sbmFtZXMoYXMubWF0cml4KGcuc3BhY2UpKV0sIGxhYmVscyhkZW5kKSwgIiIpKSAlPiUKICAjICBzZXQoImJyYW5jaGVzX2tfY29sb3IiLCB2YWx1ZSA9IGMoImdyYXk4MCIsIiM0REJCRDVGRiIsIiM5MUQxQzJGRiIgLCJncmF5ODAiLCIjRjM5QjdGRkYiLCIjRTY0QjM1RkYiLCIjM0M1NDg4RkYiKSwgayA9IDcpICU+JQogcGxvdChob3Jpej1GLCBheGVzPVQpIyx5bGltID0gYygwLDgwKSkKCmBgYApvciBqdXN0IHdpdGggcHJpbWFyeSBtYXJrZXJzCgpgYGB7ciBmaWcud2lkdGg9IDEwfQoKZGVuZCAlPiUKc2V0KCJsYWJlbHMiLCBpZmVsc2UobGFiZWxzKGRlbmQpICVpbiUgcm93bmFtZXMocGNhXzEpW3Jvd25hbWVzKHBjYV8xKSAlaW4lIHVubGlzdChsYXllcnMpXSwgbGFiZWxzKGRlbmQpLCAiIikpICU+JQogIHNldCgiYnJhbmNoZXNfa19jb2xvciIsIHZhbHVlID0gYygiZ3JheTgwIiwiIzREQkJENUZGIiwiIzkxRDFDMkZGIiAsImdyYXk4MCIsIiNGMzlCN0ZGRiIsIiNFNjRCMzVGRiIsIiMzQzU0ODhGRiIpLCBrID0gNykgJT4lCnBsb3QoaG9yaXo9RiwgYXhlcz1ULHlsaW0gPSBjKDAsMTAwKSkKCmBgYAoKTm93IHdlIGNhbiBwbG90IHRoZSBQQ0EKYGBge3J9CiMgc29tZSBtb3JlIGdlbmVzIGFzIGxhbmRtYXJrcwpjb250cm9scyA9bGlzdCgiZ2VuZXMgcmVsYXRlZCB0byBMNS82Ij1jKCJGb3hwMiIsIlRicjEiKSwgImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyI9YygiTWVmMmMiKSwgImdlbmVzIHJlbGF0ZWQgdG8gUHJvZyI9YygiTmVzIiwiU294MiIpICwgImdlbmVzIHJlbGF0ZWQgdG8gTDEiPWMoKSAsICJnZW5lcyByZWxhdGVkIHRvIEw0Ij1jKCkpIAoKIyBkYXRhZnJhbWUgdG8gYmUgYWJsZSB0byBsYWJlbCBvbmx5IHByaW1hcnkgbWFya2VycyBhbmQgY29udHJvbCBnZW5lcwp0ZXh0ZGYgPC0gcGNhXzFbcm93bmFtZXMocGNhXzEpICVpbiUgYyh1bmxpc3QobGF5ZXJzKSx1bmxpc3QoY29udHJvbHMpKSAsIF0KCiBmb3IgKG0gaW4gYygxOmxlbmd0aChjb250cm9scykpKSB7CiAgZm9yIChnIGluIGNvbnRyb2xzW1ttXV0pIHsKICAgIGlmKGcgJWluJSByb3duYW1lcyh0ZXh0ZGYpKXsKICAgICAgdGV4dGRmW2csImhpZ2hsaWdodCJdID0gbmFtZXMoY29udHJvbHNbbV0pCiAgICB9IAogIH0KfQoKIyBkZWNpZGluZyB0aGUgY29sb3JzCm15Y29sb3VycyA8LSBjKCJnZW5lcyByZWxhdGVkIHRvIEw1LzYiID0gIiMzQzU0ODhGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyI9IiNGMzlCN0ZGRiIsImdlbmVzIHJlbGF0ZWQgdG8gUHJvZyI9IiM0REJCRDVGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDEiPSIjRTY0QjM1RkYiLCJnZW5lcyByZWxhdGVkIHRvIEw0IiA9ICIjOTFEMUMyRkYiLCAibm90IG1hcmtlZCI9IiNCMDlDODVGRiIpCgojIHRvIGFzc2luZyBjb3JyZWNseSB0aGUgY2x1c3RlciBudW1iZXIgYW5kIHRoZSBjb2xvcgpteWNvbG91cnMyID0gYygiUmVsbiIsIlNhdGIyIiwiUm9yYiIsIkJjbDExYiIsIlZpbSIpCm5hbWVzKG15Y29sb3VyczIpID0gdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pCgpteWNvbG91cnMyW215Y29sb3VyczIgPT0gIlJlbG4iXSA9ICIjRTY0QjM1RkYiCm15Y29sb3VyczJbbXljb2xvdXJzMiA9PSAiU2F0YjIiXSA9ICIjRjM5QjdGRkYiCm15Y29sb3VyczJbbXljb2xvdXJzMiA9PSAiUm9yYiJdID0gIiM5MUQxQzJGRiIKbXljb2xvdXJzMltteWNvbG91cnMyID09ICJCY2wxMWIiXSA9ICIjM0M1NDg4RkYiCm15Y29sb3VyczJbbXljb2xvdXJzMiA9PSAiVmltIl0gPSAiIzREQkJENUZGIgpjb2xvcl90b19hZGQgPSB1bmlxdWUocGNhXzEkaGNsdXN0KVshdW5pcXVlKHBjYV8xJGhjbHVzdCkgJWluJSBhcy5udW1lcmljKG5hbWVzKG15Y29sb3VyczIpKV0KbmFtZXMoY29sb3JfdG9fYWRkKSA9IHVuaXF1ZShwY2FfMSRoY2x1c3QpWyF1bmlxdWUocGNhXzEkaGNsdXN0KSAlaW4lIGFzLm51bWVyaWMobmFtZXMobXljb2xvdXJzMikpXQpjb2xvcl90b19hZGRbY29sb3JfdG9fYWRkICVpbiUgCiAgICAgICAgICAgICAgICAgdW5pcXVlKHBjYV8xJGhjbHVzdClbIXVuaXF1ZShwY2FfMSRoY2x1c3QpICVpbiUgYXMubnVtZXJpYyhuYW1lcyhteWNvbG91cnMyKSldXSA9ICIjQjA5Qzg1RkYiCm15Y29sb3VyczIgPSBjKG15Y29sb3VyczIsY29sb3JfdG9fYWRkKQoKcGNhMSA9IGdncGxvdChzdWJzZXQocGNhXzEsIWhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSAgKSwgYWVzKHg9UEMxLCB5PVBDMikpICsgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsY29sb3IgPSAiI0IwOUM4NUZGIixzaXplPTEpCgojcGNhMiA9IHBjYTEgKyBnZW9tX3BvaW50KGRhdGEgPSBzdWJzZXQocGNhXzEsIGhpZ2hsaWdodCAhPSAibm90IG1hcmtlZCIgKSwgYWVzKHg9UEMxLCB5PVBDMiwgY29sb3VyPWhjbHVzdCksc2l6ZT0yLjUsYWxwaGEgPSAwLjkpIApwY2EyID0gcGNhMSArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChwY2FfMSwgaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pICksIGFlcyh4PVBDMSwgeT1QQzIsIGNvbG91cj1hcy5jaGFyYWN0ZXIoaGNsdXN0KSksc2l6ZT0xLGFscGhhID0gMC41KSArIAogc2NhbGVfY29sb3JfbWFudWFsKCAiU3RhdHVzIiwgdmFsdWVzID0gbXljb2xvdXJzMikgICsKICBzY2FsZV9maWxsX21hbnVhbCggIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID10ZXh0ZGYgLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSByb3duYW1lcyh0ZXh0ZGYpLGZpbGw9YXMuY2hhcmFjdGVyKGhjbHVzdCkpLAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC41LCAKICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gcm93bmFtZXModGV4dGRmKSksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdibGFjaycsCiAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0KSArCiAgZ2d0aXRsZSgiUENBIikgKwogIHRoZW1lX2xpZ2h0KGJhc2Vfc2l6ZT0xMCkgKwogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9Iml0YWxpYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0iIzNDNTQ4OEZGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWhlaWdodD0xLjIsbWFyZ2luID0gbWFyZ2luKHQgPSA1LCBiID0gLTE1KSksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICMgdGl0bCkKCnBjYTIgIysgZ2VvbV9lbmNpcmNsZShkYXRhID0gcGNhXzEsIGFlcyhncm91cD1oY2x1c3QpKSAKYGBgCgp0LVNORSBjb2RlIGFuZCBwbG90CgpgYGB7cn0KIyBydW4gdGhlIHQtU05FCmNsLmdlbmVzLnRzbmUgPSBSdHNuZShnLnNwYWNlICxpbml0aWFsX2RpbXMgPSAxMDAsIGRpbXMgPSAyLCBwZXJwbGV4aXR5PTMwLGV0YSA9IDIwMCwgdmVyYm9zZT1GLCBtYXhfaXRlciA9IDMwMDAsdGhldGE9MC40LG51bV90aHJlYWRzID0gMTAscGNhX2NlbnRlciA9IFQsIHBjYV9zY2FsZSA9IEZBTFNFLCBub3JtYWxpemUgPSBUICkKCmRfdHNuZV8xID0gYXMuZGF0YS5mcmFtZShjbC5nZW5lcy50c25lJFkpCnJvd25hbWVzKGRfdHNuZV8xKSA9IHJvd25hbWVzKGcuc3BhY2UpCgpkX3RzbmVfMSA9IGRfdHNuZV8xW29yZGVyLmRlbmRyb2dyYW0oZGVuZCksXQoKIyBzYXZlIHRoZSBjbHVzdGVyIG51bWViciBpbnNpZGUgYSBkYXRhZnJhbWUgd2l0aCB0aGUgdC1TTkUgaW5mb3JtYXRpb24KZF90c25lXzEkaGNsdXN0ID0gY3V0CgpkX3RzbmVfMSRuYW1lcyA9IHJvd25hbWVzKGRfdHNuZV8xKQoKIyBhcyBiZWZvcmUgdG8gbGFiZWwgb25seSBzb21lIGdlbmVzCnRleHRkZiA8LSBkX3RzbmVfMVtyb3duYW1lcyhkX3RzbmVfMSkgJWluJSBjKHVubGlzdChsYXllcnMpLHVubGlzdChjb250cm9scykpLF0KCmZvciAobSBpbiBjKDE6bGVuZ3RoKGNvbnRyb2xzKSkpIHsKICBmb3IgKGcgaW4gY29udHJvbHNbW21dXSkgewogICAgaWYoZyAlaW4lIHJvd25hbWVzKHRleHRkZikpewogICAgICB0ZXh0ZGZbZywiaGlnaGxpZ2h0Il0gPSBuYW1lcyhjb250cm9sc1ttXSkKICAgIH0gCiAgfQp9CgoKIHAxID0gZ2dwbG90KHN1YnNldChkX3RzbmVfMSwhaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pKSwgYWVzKHg9VjEsIHk9VjIpKSArICBnZW9tX3BvaW50KGFscGhhID0gMC4zLCBjb2xvciA9ICIjQjA5Qzg1RkYiLCBzaXplPTEpCgpwMiA9IHAxICsgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KGRfdHNuZV8xLCBoY2x1c3QgJWluJSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkgKSwgYWVzKHg9VjEsIHk9VjIsIGNvbG91cj1hcy5jaGFyYWN0ZXIoaGNsdXN0KSksc2l6ZT0xLGFscGhhID0gMC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgc2NhbGVfZmlsbF9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgeGxhYigiIikgKyB5bGFiKCIiKSsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSBuYW1lcyxmaWxsPWFzLmNoYXJhY3RlcihoY2x1c3QpKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSBuYW1lcyksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdibGFjaycsCiAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0KSArCiAgZ2d0aXRsZSgidC1TTkUiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9Iml0YWxpYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0iIzNDNTQ4OEZGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWhlaWdodD0xLjIsbWFyZ2luID0gbWFyZ2luKHQgPSA1LCBiID0gLTE1KSksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICMgdGl0bCkKcDIKYGBgCkNvZGUgdG8gY3JlYXRlIGFuIGl0ZXJhY3RpdmUgcGxvdC4gVGhpcyBjYW4gYmUgbW9kaWZpZWQgdG8gYmUgdXNlZCB3aXRoIGFsbCB0aGUgcGxvdHMuCgpgYGB7ciBlY2hvPVRSVUV9CgpwID0gZ2dwbG90KGRfdHNuZV8xLCBhZXMoeD1WMSwgeT1WMiwgdGV4dD0gcGFzdGUoImdlbmU6ICIsbmFtZXMpKSkgKyAgCiAgZ2VvbV9wb2ludChzaXplPTIsIGFlcyhjb2xvdXI9YXMuY2hhcmFjdGVyKGhjbHVzdCkpLCBhbHBoYT0wLjgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgZ2d0aXRsZSgidC1TTkUiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSkKCmdncGxvdGx5KHApCmBgYAoKTXVsdGlkaW1lbnNpb25hbCBzY2FsaW5nIChNRFMpIGFuZCBwbG90CmBgYHtyfQojIHJ1biB0aGUgTURTCmdlbmVzLmRpc3QuZXVjID0gIGRpc3QoZy5zcGFjZSwgbWV0aG9kID0gICJldWNsaWRlYW4iKQojZml0IDwtIGlzb01EUyhnZW5lcy5kaXN0LmV1YykgIyBub3QgbGluZWFyCmZpdCA8LSBpc29NRFMoZ2VuZXMuZGlzdC5ldWMpCgpmaXQuZ2VuZXMgPSBhcy5kYXRhLmZyYW1lKGZpdCRwb2ludHMpCgpmaXQuZ2VuZXMgPSBmaXQuZ2VuZXNbb3JkZXIuZGVuZHJvZ3JhbShkZW5kKSxdCgpmaXQuZ2VuZXMkaGNsdXN0ID0gY3V0CgoKZml0LmdlbmVzJG5hbWVzID0gcm93bmFtZXMoZml0LmdlbmVzKQoKbXljb2xvdXJzMyA8LSBjKCJjbHVzdGVyIEw1LzYgbWFya2VycyIgPSAiIzNDNTQ4OEZGIiwiY2x1c3RlciBMMi8zIG1hcmtlcnMiPSIjRjM5QjdGRkYiLCJjbHVzdGVyIFByb2cgbWFya2VycyI9IiM0REJCRDVGRiIsImNsdXN0ZXIgTDEgbWFya2VycyI9IiNFNjRCMzVGRiIsImNsdXN0ZXIgTDQgbWFya2VycyIgPSAiIzkxRDFDMkZGIiwgIm5vdCBpZGVudGlmaWVkIGNsdXN0ZXIiPSIjQjA5Qzg1RkYiKQoKI2ZpdC5nZW5lcyRoY2x1c3QgPSBmYWN0b3IoY3V0cmVlKGhjLm5vcm0sIDcpKQp1c2VkID0gdmVjdG9yKCkKZm9yIChrIGluIGMoMTpsZW5ndGgobGF5ZXJzKSkpIHsKICAjcHJpbnQoaykKICB0dCA9YXMubnVtZXJpYyhjdXRbbGF5ZXJzW1trXV1dWzFdKQogIGZpdC5nZW5lc1tmaXQuZ2VuZXMkaGNsdXN0ID09IHR0LCJjbHVzdGVyIl0gPSBwYXN0ZSgiY2x1c3RlciIsbmFtZXMobGF5ZXJzW2tdKSwibWFya2VycyIsIHNlcCA9ICIgIiApCiAgdXNlZCA9IGModXNlZCxjdXRbbGF5ZXJzW1trXV1dWzFdKQp9CgpmaXQuZ2VuZXNbZml0LmdlbmVzJGhjbHVzdCAlaW4lICh1bmlxdWUoZml0LmdlbmVzJGhjbHVzdClbIXVuaXF1ZShmaXQuZ2VuZXMkaGNsdXN0KSAlaW4lIHVzZWRdKSxdJGNsdXN0ZXIgPSAibm90IGlkZW50aWZpZWQgY2x1c3RlciIKCnRleHRkZiA8LSBmaXQuZ2VuZXNbcm93bmFtZXMoZml0LmdlbmVzKSAlaW4lIGModW5saXN0KGxheWVycyksdW5saXN0KGNvbnRyb2xzKSksXQoKICAgZjEgPSBnZ3Bsb3Qoc3Vic2V0KGZpdC5nZW5lcywhaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pICksIGFlcyh4PVYxLCB5PVYyKSkgKyAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAiI0IwOUM4NUZGIiwgc2l6ZT0xKQoKZjIgPSBmMSArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChmaXQuZ2VuZXMsIGhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSApLCAKICAgICAgICAgICAgICAgICAgICAgYWVzKHg9VjEsIHk9VjIsIGNvbG91cj1jbHVzdGVyKSwgc2l6ZT0xLGFscGhhID0gMC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMzKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMzKSAgKyAKICB4bGFiKCIiKSArIHlsYWIoIiIpKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBWMSwgeSA9IFYyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZiksZmlsbD1jbHVzdGVyKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSJib3RoIiwKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBWMSwgeSA9IFYyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZikpLAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLCAKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdndGl0bGUoIk1EUyIpICsKICB0aGVtZV9saWdodChiYXNlX3NpemU9MTApICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSIjM0M1NDg4RkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0wLjAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0PTEuMixtYXJnaW4gPSBtYXJnaW4odCA9IDUsIGIgPSAtMTUpKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMzQzU0ODhGRiIsZmFjZSA9Iml0YWxpYyIgKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgICMgdGl0bCkKCgpmMiAjKyBnZW9tX2VuY2lyY2xlKGRhdGEgPSBmaXQuZ2VuZXMsIGFlcyhncm91cD1gNV9jbHVzdGVyc2ApKSAKYGBgCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCg==